﻿using System;
using System.Collections.Generic;
using System.Text;

using Semantics.Base;

namespace Semantics.IR
{
    public class Semantizer : ISemantizer
    {
        KnowledgeBase.KnowledgeSet KnowledgeSet;
        public Semantizer(KnowledgeBase.KnowledgeSet knowledgeset)
        {
            this.KnowledgeSet = knowledgeset;
        }
        public Graph Semantize(SemanticNode semanticnode)
        {
            Graph graph=new Graph();
            graph.Ontology = this.KnowledgeSet.Ontology;
            graph.RootNode = Semantize(semanticnode, graph);
            return graph;
        }
        Node Semantize(SemanticNode semanticnode, Graph graph)
        {
            if (semanticnode.Pattern == null)//It is a phrase)
            {
                Node node = GraphUtility.ResolveOrCreate(graph, semanticnode.Class);
                if (node.Class == null)
                    node.Class = semanticnode.Class;
                return node;
            }
            else
            {
                NodeList nodes = new NodeList();
                for (int i = 0; i < semanticnode.Children.Count; i++)
                {
                    SemanticNode childnode = semanticnode.Children[i].Child;
                    if (childnode.Pattern != null)
                    {//This is a phrase
                        Node node = Semantize(childnode, graph);
                        nodes.Add(node);
                    }
                    else
                    {
                        Node node = new Node(childnode.Class.Value);//??? Referring Expression
                        node.Class = childnode.Class;
                        nodes.Add(node);
                    }
                }
                return Semantize(semanticnode.Pattern, semanticnode, nodes, graph);
            }
        }

        Node Semantize(SemanticPattern pattern, SemanticNode semanticnode, INodeList nodes, Graph graph)
        {
            switch (pattern.Type)
            {
                case SemanticPattern.PatternType.Absorbing:
                    {
                        return nodes[pattern.CoreRole];
                    }
                case SemanticPattern.PatternType.Subsuming:
                    {
                        Node core = nodes[pattern.CoreRole];
                        Node existcode = graph.ResolveNode(core.Value);
                        if (existcode == null)
                        {
                            existcode = new Node(core.Value);
                            graph.EnrollNode(existcode);
                        }
                        Node subsumednode = new Node();
                        subsumednode.Class = core.Class;
                        if (core.Is("[事物]") || core.Is("[度量]"))
                            subsumednode.Value = semanticnode.Value;
                        else
                            subsumednode.Value = core.Value + "/" + subsumednode.Id.ToString();
                        graph.EnrollNode(subsumednode);
                        Edge edge = new Edge(this.KnowledgeSet.Ontology.IsKindOfNode, subsumednode, existcode);
                        graph.EnrollEdge(edge);
                        for (int i = 0; i < pattern.Roles.Length; i++)
                        {
                            if (i == pattern.CoreRole)
                                continue;
                            
                            SemanticRole role = pattern.Roles[i];
                            if (role.RoleType == SemanticRole.SemanticRoleType.Functor)
                                continue;
                            Node attributetypenode = null;
                            switch (role.Attribute)
                            {
                                case "[属性]":
                                    {
                                        attributetypenode = this.KnowledgeSet.Ontology.ResolveNode("[属性]");
                                        break;
                                    }
                                case "[Owner]":
                                    attributetypenode = this.KnowledgeSet.Ontology.ResolveNode("属于");
                                    break;
                                default:
                                    attributetypenode = role.AttributeNameNode;
                                    break;
                            }
                            Edge attributeedge = Edge.ConnectNode(subsumednode, attributetypenode, nodes[i]);
                            if(graph.ResolveNode(attributeedge.Incoming)==null)
                                graph.EnrollNode(attributeedge.Incoming);
                            graph.EnrollEdge(attributeedge);
                        }
                        return subsumednode;
                    }
                case SemanticPattern.PatternType.Relational:
                    {
                        //目前数据库中SemanticPattern的角色类型标注不统一
                        //有[A]/[B]和[主体]/[客体]两种,需要兼容处理
                        //未来要统一处理
                        SemanticRole roleA = pattern.GetSemanticRole("[A]");
                        SemanticRole roleB = pattern.GetSemanticRole("[B]");
                        SemanticRole roleRelation = pattern.GetSemanticRole("[关系]");
                        if(roleA==null)
                            roleA = pattern.GetSemanticRole("[主体]");
                        if(roleB == null)
                            roleB = pattern.GetSemanticRole("[客体]");
                        if(roleA==null&&roleB==null&&roleRelation==null)
                            throw new Exception("Invalid pattern '"+pattern+"', no enough role(s)");
                        Node outgoing=nodes[roleA.RoleIndex];
                        if(graph.ResolveNode(outgoing)==null)
                            graph.EnrollNode(outgoing);
                        Node incoming = nodes[roleB.RoleIndex];
                        if (graph.ResolveNode(incoming) == null)
                            graph.EnrollNode(incoming);
                        Node edgetype = graph.ResolveNode(nodes[roleRelation.RoleIndex]);
                        if (edgetype == null)
                        {
                            edgetype = new Node(nodes[roleRelation.RoleIndex].Value);
                            edgetype.Class = nodes[roleRelation.RoleIndex].Class;
                            graph.EnrollNode(edgetype);
                        }
                        Edge edge = Edge.ConnectNode(outgoing, edgetype, incoming);
                        graph.EnrollEdge(edge);
                        return nodes[roleA.RoleIndex];
                        //break;
                    }
                default:
                    throw new NotImplementedException();
            }
        }
   
    }
}
